home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / console.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  77KB  |  2,397 lines

  1. /*
  2.  * All video and keyboard functions were gathered into one file.
  3.  *
  4.  * In version 3.2, this file was split into 3 sections:  1) unix curses
  5.  * made to look and feel like a PC, 2) our PC hardware specific stuff,
  6.  * and 3) hardware independent stuff.
  7.  *
  8.  * This file contains the keyboard and video i/o stuff.  Most of this stuff
  9.  * is specific to the PC hardware, but it should be easily modified when
  10.  * porting to other platforms.  With a few key functions written in
  11.  * assembly, we have fairly fast video performance and good keyboard control.
  12.  * Incidentally, the commented C code in the functions perform the same
  13.  * function as the assembly code.  In earlier versions of TDE, I didn't
  14.  * update the commented C code when I changed the assembly code.  The
  15.  * C and assembly should be equivalent in version 2.2.
  16.  *
  17.  * Although using a curses type package would be more portable, curses
  18.  * can be slow on PCs.  Let's keep our video and keyboard routines in
  19.  * assembly.  I feel the need for speed.
  20.  *
  21.  * Being that TDE 2.2 keeps an accurate count of characters in each line, we
  22.  * can allow the user to enter any ASCII or Extended ASCII key.
  23.  *
  24.  * Determining the video adapter type on the PC requires a function.  In
  25.  *  TDE, that function is:
  26.  *
  27.  *                void video_config( struct vcfg *cfg )
  28.  *
  29.  * video_config( ) is based on Appendix C in _Programmer's Guide to
  30.  *  PC & PS/2 Video Systems_ by Richard Wilton.
  31.  *
  32.  * See:
  33.  *
  34.  *   Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_,
  35.  *    Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521.
  36.  *    ISBN 1-55615-103-9.
  37.  *
  38.  *
  39.  * New editor name:  TDE, the Thomson-Davis Editor.
  40.  * Author:           Frank Davis
  41.  * Date:             June 5, 1991, version 1.0
  42.  * Date:             July 29, 1991, version 1.1
  43.  * Date:             October 5, 1991, version 1.2
  44.  * Date:             January 20, 1992, version 1.3
  45.  * Date:             February 17, 1992, version 1.4
  46.  * Date:             April 1, 1992, version 1.5
  47.  * Date:             June 5, 1992, version 2.0
  48.  * Date:             October 31, 1992, version 2.1
  49.  * Date:             April 1, 1993, version 2.2
  50.  * Date:             June 5, 1993, version 3.0
  51.  * Date:             August 29, 1993 version 3.1
  52.  * Date:             November 13, version 3.2
  53.  * Date:             June 5, version 4.0
  54.  *
  55.  * This code is released into the public domain, Frank Davis.
  56.  * You may distribute it freely.
  57.  */
  58.  
  59.  
  60. #include "tdestr.h"
  61. #include "common.h"
  62. #include "define.h"
  63. #include "tdefunc.h"
  64.  
  65. #if defined( __UNIX__ )
  66. /*
  67.  **********************************************************************
  68.  ******************************  PART 1  ******************************
  69.  **********************************************************************
  70.  *
  71.  * Let's try to make unix have the look and feel of a PC.
  72.  */
  73.  
  74.  
  75. /*
  76.  * Name:    video_config
  77.  * Purpose: simulate a call the BIOS keyboard status subfunction
  78.  * Date:    November 13, 1993
  79.  * Passed:  cfg:  not used
  80.  * Notes:   curses has three (?) cursor shapes:  invisible, normal, large.
  81.  */
  82. void video_config( struct vcfg *cfg )
  83. {
  84. /*
  85.    g_display.insert_cursor =
  86.                  mode.cursor_size == SMALL_INS ? CURSES_SMALL : CURSES_LARGE;
  87.    g_display.overw_cursor =
  88.                  mode.cursor_size == SMALL_INS ? CURSES_LARGE : CURSES_SMALL;
  89. */
  90.  
  91.    g_display.insert_cursor = g_display.overw_cursor = CURSES_SMALL;
  92.    if (mode.insert)
  93.       g_display.curses_cursor = g_display.insert_cursor;
  94.    else
  95.       g_display.curses_cursor = g_display.overw_cursor;
  96. }
  97.  
  98.  
  99. /*
  100.  * Name:    getkey
  101.  * Purpose: use unix curses to get keyboard input
  102.  * Date:    November 13, 1993
  103.  * Passed:  None
  104.  * Notes:   the getch( ) function is not part of the ANSI C standard.
  105.  *            most (if not all) PC C compilers include getch( ) with the
  106.  *            conio stuff.  in unix, getch( ) is in the curses package.
  107.  *          in TDE, lets try to map the curses function keys to their
  108.  *            "natural" positions on PC hardware.  most of the key mapping
  109.  *            is at the bottom of default.h.
  110.  *          this function is based on the ncurses package in Linux.  It
  111.  *            probably needs to be modified for curses in other unices.
  112.  */
  113. int getkey( void )
  114. {
  115. unsigned key;
  116.  
  117.    key = getch( );
  118.  
  119.    /*
  120.     * map the Control keys to their natural place in TDE.
  121.     */
  122.    if (key < 32)
  123.       key += 430;
  124.    else if (key > 255) {
  125.  
  126.       /*
  127.        * map ncurses keys to their natural place in TDE.
  128.        * ncurses defines function keys in the range 256-408.
  129.        */
  130.       if (key > 408)
  131.          key = 256;
  132.       key = curses_to_tde[key - 256];
  133.    }
  134.    return( key );
  135. }
  136.  
  137.  
  138. /*
  139.  * Name:    waitkey
  140.  * Purpose: nothing right now
  141.  * Date:    November 13, 1993
  142.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  143.  * Returns: 1 if no key ready, 0 if key is waiting
  144.  * Notes:   we might do something with this function later...
  145.  */
  146. int  waitkey( int enh_keyboard )
  147. {
  148.    return( 0 );
  149. }
  150.  
  151.  
  152. /*
  153.  * Name:    flush_keyboard
  154.  * Purpose: flush keys from the keyboard buffer.  flushinp is a curses func.
  155.  * Date:    November 13, 1993
  156.  * Passed:  none
  157.  */
  158. void flush_keyboard( void )
  159. {
  160.    flushinp( );
  161. }
  162.  
  163.  
  164. /*
  165.  * Name:    xygoto
  166.  * Purpose: To move the cursor to the required column and line.
  167.  * Date:    November 13, 1993
  168.  * Passed:  col:    desired column (0 up to max)
  169.  *          line:   desired line (0 up to max)
  170.  * Notes;   on the PC, we use col = -1 and line = -1 to turn the cursor off.
  171.  *            in unix, we try to trap the -1's.
  172.  *          curs_set is a curses function.
  173.  */
  174. void xygoto( int col, int line )
  175. {
  176.    if (col < 0 || line < 0) {
  177.       curs_set( CURSES_INVISBL );
  178.       g_display.curses_cursor = CURSES_INVISBL;
  179.    } else {
  180.  
  181.       /*
  182.        * if the unix cursor is invisible, lets turn it back on.
  183.        */
  184.       if (g_display.curses_cursor == CURSES_INVISBL) {
  185. /*
  186.          if (mode.insert == TRUE) {
  187.             if (g_display.insert_cursor == SMALL_INS)
  188.                set_cursor_size( CURSES_SMALL );
  189.             else
  190.                set_cursor_size( CURSES_LARGE );
  191.          } else {
  192.             if (g_display.insert_cursor == SMALL_INS)
  193.                set_cursor_size( CURSES_LARGE );
  194.             else
  195.                set_cursor_size( CURSES_SMALL );
  196.          }
  197. */
  198.          set_cursor_size( CURSES_SMALL );
  199.          g_display.curses_cursor = CURSES_SMALL;
  200.       }
  201.       move( line, col );
  202.    }
  203. }
  204.  
  205.  
  206. /*
  207.  * Name:    update_line
  208.  * Purpose: Display the current line in window
  209.  * Date:    November 13, 1993
  210.  * Passed:  window:  pointer to current window
  211.  * Notes:   use the curses mvaddch( ) function to put char + attribute
  212.  *           on the screen.
  213.  *          let's check for control characters before they get to curses.
  214.  *            unix and/or curses is brain-damaged when it comes to
  215.  *            control characters and extended ASCII characters.
  216.  */
  217. void update_line( TDE_WIN *window )
  218. {
  219. text_ptr text;      /* current character of orig begin considered */
  220. int  attr;          /* index into TDE's chtype table */
  221. int  line;
  222. int  col;
  223. int  bcol;
  224. int  bc;
  225. int  ec;
  226. int  normal;
  227. int  block;
  228. int  max_col;
  229. int  block_line;
  230. int  len;
  231. int  show_eol;
  232. unsigned int  c;
  233. long rline;
  234. file_infos *file;
  235. chtype curses_attribute;        /* chtype is defined in curses.h */
  236.  
  237.    /*
  238.     * we don't use this function to display the EOF message.
  239.     * return if this display is turned off.
  240.     */
  241.    if (window->rline > window->file_info->length || window->ll->len == EOF
  242.              || !g_status.screen_display)
  243.       return;
  244.  
  245.    file = window->file_info;
  246.    max_col = window->end_col + 1 - window->start_col;
  247.    line = window->cline;
  248.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  249.    block = g_display.block_color;
  250.    show_eol = mode.show_eol;
  251.  
  252.    /*
  253.     * figure which line to display.
  254.     * actually, we could be displaying any line in any file.  we display
  255.     *  the line_buffer only if window->ll == g_status.buff_node
  256.     *  and window->ll-line has been copied to g_status.line_buff.
  257.     */
  258.    text = window->ll->line;
  259.    len  = window->ll->len;
  260.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  261.       text = (text_ptr)g_status.line_buff;
  262.       len  = g_status.line_buff_len;
  263.    }
  264.    if (mode.inflate_tabs)
  265.       text = tabout( text, &len );
  266.  
  267.    /*
  268.     * lets look at the base column.  if the line to display is shorter
  269.     *  than the base column, then set text to eol and we can't see the
  270.     *  eol either.
  271.     */
  272.    bc = window->bcol;
  273.    if (bc > 0) {
  274.       if (text == NULL) {
  275.          show_eol = FALSE;
  276.          len = 0;
  277.       } else {
  278.          if ((col = len) < bc) {
  279.             bc = col;
  280.             show_eol = FALSE;
  281.          }
  282.          text += bc;
  283.          len  -= bc;
  284.       }
  285.    }
  286.  
  287.    /*
  288.     * for display purposes, set the line length to screen width if line
  289.     *  is longer than screen.  our assembly routine uses bytes and the
  290.     *  the line length can be longer than a byte.
  291.     */
  292.    if (len > max_col)
  293.       len = max_col;
  294.  
  295.    bcol = window->bcol;
  296.    rline = window->rline;
  297.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  298.       block_line = TRUE;
  299.    else
  300.       block_line = FALSE;
  301.  
  302.    /*
  303.     * do this if 1) a box block is marked, or 2) a stream block begins
  304.     *  and ends on the same line.
  305.     */
  306.    if (block_line == TRUE && (file->block_type == BOX ||
  307.          (file->block_type == STREAM &&
  308.          rline == file->block_br && rline == file->block_er))) {
  309.  
  310.       /*
  311.        * start with the bc and ec equal to physical block marker.
  312.        */
  313.       bc = file->block_bc;
  314.       ec = file->block_ec;
  315.       if (ec < bcol || bc >= bcol + max_col)
  316.          /*
  317.           * we can't see block if ending column is less than the base col or
  318.           *  the beginning column is greater than max_col.
  319.           */
  320.          ec = bc = max_col + 1;
  321.       else if (ec < bcol + max_col) {
  322.          /*
  323.           * if the ec is less than the max column, make ec relative to
  324.           *  base column then figure the bc.
  325.           */
  326.          ec = ec - bcol;
  327.          if (bc < bcol)
  328.             bc = 0;
  329.          else
  330.             bc = bc - bcol;
  331.       } else if (bc < bcol + max_col) {
  332.          /*
  333.           * if the bc is less than the max column, make bc relative to
  334.           *  base column then figure the ec.
  335.           */
  336.          bc = bc - bcol;
  337.          if (ec > bcol + max_col)
  338.             ec = max_col;
  339.          else
  340.             ec = ec - bcol;
  341.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  342.          /*
  343.           * if the block is wider than the screen, make bc start at the
  344.           *  logical begin and make ec end at the logical end of the
  345.           *  window.
  346.           */
  347.          bc = 0;
  348.          ec = max_col;
  349.       }
  350.       bcol = window->start_col;
  351.       for (col=0; col < max_col; col++, bcol++) {
  352.          attr = normal;
  353.          if (col >= bc && col <= ec)
  354.             attr = block;
  355.          if (col < len)
  356.             c = *text++;
  357.          else if (col == len && show_eol)
  358.             c = EOL_CHAR;
  359.          else
  360.             c = ' ';
  361.          if (c < 32)
  362.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  363.          else if (c >= 127)
  364.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  365.          else
  366.             mvaddch( line, bcol, c | tde_color_table[attr] );
  367.       }
  368.    } else if (block_line == TRUE && file->block_type == STREAM &&
  369.               (rline == file->block_br || rline == file->block_er)) {
  370.       if (rline == file->block_br)
  371.          bc = file->block_bc;
  372.       else {
  373.          bc = file->block_ec + 1;
  374.          ec = normal;
  375.          normal = block;
  376.          block = ec;
  377.       }
  378.  
  379.       ec = max_col + 1;
  380.       if (bc < bcol)
  381.          bc = 0;
  382.       else if (bc < bcol + max_col)
  383.          bc = bc - bcol;
  384.       else
  385.          bc = max_col + 1;
  386.       bcol = window->start_col;
  387.  
  388.       for (col=0; col < max_col; col++, bcol++) {
  389.          attr = normal;
  390.          if (col >= bc && col <= ec)
  391.             attr = block;
  392.          if (col < len)
  393.             c = *text++;
  394.          else if (col == len && show_eol)
  395.             c = EOL_CHAR;
  396.          else
  397.             c = ' ';
  398.          if (c < 32)
  399.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  400.          else if (c >= 127)
  401.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  402.          else
  403.             mvaddch( line, bcol, c | tde_color_table[attr] );
  404.       }
  405.    } else {
  406.       if (block_line)
  407.          attr = block;
  408.       else
  409.          attr = normal;
  410.  
  411.       assert( len >= 0 );
  412.       assert( len <= g_display.ncols );
  413.  
  414.       curses_attribute = tde_color_table[attr];
  415.       bcol = window->start_col;
  416.       for (col=0; col < max_col; col++, bcol++) {
  417.          if (col < len)
  418.             c = *text++;
  419.          else if (col == len && show_eol)
  420.             c = EOL_CHAR;
  421.          else
  422.             c = ' ';
  423.          if (c < 32)
  424.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  425.          else if (c >= 127)
  426.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  427.          else
  428.             mvaddch( line, bcol, c | curses_attribute );
  429.       }
  430.    }
  431. }
  432.  
  433.  
  434. /*
  435.  * Name:    c_output
  436.  * Purpose: Output one character on prompt lines
  437.  * Date:    November 13, 1993
  438.  * Passed:  c:     character to output to screen
  439.  *          col:   col to display character
  440.  *          line:  line number to display character
  441.  *          attr:  attribute of character
  442.  * Returns: none
  443.  */
  444. void c_output( int c, int col, int line, int attr )
  445. {
  446. register unsigned int uc;
  447.  
  448.    uc = c;
  449.  
  450.    if (uc < 32)
  451.       mvaddch( line, col, (uc+64) | tde_color_table[g_display.curl_color] );
  452.    else if (uc >= 127)
  453.       mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] );
  454.    else
  455.       mvaddch( line, col, uc | tde_color_table[attr] );
  456. }
  457.  
  458.  
  459. /*
  460.  * Name:    s_output
  461.  * Purpose: To output a string
  462.  * Date:    November 13, 1993
  463.  * Passed:  s:     string to output
  464.  *          line:  line to display
  465.  *          col:   column to begin display
  466.  *          attr:  color to display string
  467.  * Notes:   This function is used to output most strings not part of file text.
  468.  */
  469. void s_output( char *s, int line, int col, int attr )
  470. {
  471. int max;
  472. register unsigned int uc;
  473.  
  474.    max = g_display.ncols;
  475.    if (line == g_display.mode_line  &&  (strlen( s ) + col >= g_display.ncols))
  476.       max--;
  477.  
  478.    while ((uc = (unsigned int)*s)  &&  col < max) {
  479.       if (uc < 32)
  480.          mvaddch( line, col, (uc + 64) | tde_color_table[g_display.curl_color] );
  481.       else if (uc >= 127)
  482.          mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] );
  483.       else
  484.          mvaddch( line, col, uc | tde_color_table[attr] );
  485.       col++;
  486.       s++;
  487.    }
  488. }
  489.  
  490.  
  491. /*
  492.  * Name:    eol_clear
  493.  * Purpose: To clear the line from col to max columns
  494.  * Date:    November 13, 1993
  495.  * Passed:  col:   column to begin clear
  496.  *          line:  line to clear
  497.  *          attr:  color to clear
  498.  * Notes:   use unix curses clrtoeol( ) to clear the line.
  499.  */
  500. void eol_clear( int col, int line, int attr )
  501. {
  502.    move( line, col );
  503.    clrtoeol( );
  504. }
  505.  
  506.  
  507. /*
  508.  * Name:    window_eol_clear
  509.  * Purpose: To clear the line from start_col to end_col
  510.  * Date:    November 13, 1993
  511.  * Passed:  window:  pointer to window
  512.  *          attr:  color to clear
  513.  * Notes:   don't use unix curses clrtoeol, because we could be in a
  514.  *            vertical window.  lines don't always extend to end of screen
  515.  *            in a vertical window.
  516.  */
  517. void window_eol_clear( TDE_WIN *window, int attr )
  518. {
  519. int max_col;
  520. chtype c;       /* chtype is defined in curses.h */
  521.  
  522.    if (!g_status.screen_display)
  523.       return;
  524.  
  525.    assert( attr >= 0 && attr < 128 );
  526.  
  527.    c = ' ' | tde_color_table[attr];
  528.    max_col = window->start_col;
  529.    while (max_col <= window->end_col)
  530.       mvaddch( window->cline, max_col++, c );
  531. }
  532.  
  533.  
  534. /*
  535.  * Name:    hlight_line
  536.  * Date:    November 13, 1993
  537.  * Passed:  x:     column to begin hi lite
  538.  *          y:     line to begin hi lite
  539.  *          lgth:  number of characters to hi lite
  540.  *          attr:  attribute color
  541.  */
  542. void hlight_line( int x, int y, int lgth, int attr )
  543. {
  544. int max;
  545.  
  546.    max = g_display.ncols;
  547.    if (y == g_display.mode_line)
  548.       max--;
  549.  
  550.    for (; lgth > 0 && x < max; x++, lgth--) {
  551.       move( y, x );
  552.       addch( (inch( ) & A_CHARTEXT) | tde_color_table[attr] );
  553.    }
  554.    refresh( );
  555. }
  556.  
  557.  
  558. /*
  559.  * Name:    cls
  560.  * Purpose: clear screen
  561.  * Date:    November 13, 1993
  562.  * Notes:   Call the curses clear screen function.
  563.  */
  564. void cls( void )
  565. {
  566.    touchwin( curscr );
  567.    clear( );
  568.    refresh( );
  569. }
  570.  
  571.  
  572. /*
  573.  * Name:    set_cursor_size
  574.  * Purpose: To set cursor size according to insert mode.
  575.  * Date:    November 13, 1993
  576.  * Passed:  csize:  not used in unix curses
  577.  * Notes:   use the global display structures to set the cursor size
  578.  *          curs_set( ) is a curses function.
  579.  */
  580. void set_cursor_size( int csize )
  581. {
  582. /*
  583.    if (mode.insert == TRUE) {
  584.       if (g_display.insert_cursor == SMALL_INS)
  585.          curs_set( CURSES_SMALL );
  586.       else
  587.          curs_set( CURSES_LARGE );
  588.    } else {
  589.       if (g_display.insert_cursor == SMALL_INS)
  590.          curs_set( CURSES_LARGE );
  591.       else
  592.          curs_set( CURSES_SMALL );
  593.    }
  594. */
  595.    curs_set( CURSES_SMALL );
  596.    g_display.curses_cursor = CURSES_SMALL;
  597. }
  598.  
  599.  
  600. /*
  601.  * Name:    set_overscan_color
  602.  * Purpose: To set overscan color
  603.  * Date:    November 13, 1993
  604.  * Passed:  color:  overscan color
  605.  * Notes:   i'm not sure how to set the overscan in Linux (yet?).
  606.  */
  607. void set_overscan_color( int color )
  608. {
  609. }
  610.  
  611.  
  612. /*
  613.  * Name:    save_screen_line
  614.  * Purpose: To save the characters and attributes of a line on screen.
  615.  * Date:    November 13, 1993
  616.  * Passed:  col:    desired column, usually always zero
  617.  *          line:   line on screen to save (0 up to max)
  618.  *          screen_buffer:  buffer for screen contents, must be >= 80 chtype
  619.  * Notes:   Save the contents of the line on screen where prompt is
  620.  *           to be displayed.
  621.  */
  622. void save_screen_line( int col, int line, chtype *screen_buffer )
  623. {
  624. int i;
  625.  
  626.    for (i=0; col < g_display.ncols; col++, i++)
  627.       screen_buffer[i] = mvinch( line, col );
  628. }
  629.  
  630.  
  631. /*
  632.  * Name:    restore_screen_line
  633.  * Purpose: To restore the characters and attributes of a line on screen.
  634.  * Date:    November 13, 1993
  635.  * Passed:  col:    usually always zero
  636.  *          line:   line to restore (0 up to max)
  637.  *          screen_buffer:  buffer for screen contents, must be >= 80 chtype
  638.  * Notes:   Restore the contents of the line on screen where the prompt
  639.  *           was displayed
  640.  */
  641. void restore_screen_line( int col, int line, chtype *screen_buffer )
  642. {
  643. int i;
  644.  
  645.    for (i=0; col < g_display.ncols; col++, i++)
  646.       mvaddch( line, col, screen_buffer[i] );
  647.    refresh( );
  648. }
  649.  
  650.  
  651.  
  652. /*
  653.  * Name:    save_minor_area
  654.  * Purpose: save text and attribute under the pulled menu
  655.  * Date:    November 13, 1993
  656.  * Passed:  buffer: storage for text and attribute
  657.  *          wid: width of the pulled menu
  658.  *          len: length of pulled menu
  659.  *          row: starting row of pulled menu
  660.  *          col: starting column of pulled menu
  661.  * Notes:   use curses to get char and attr
  662.  */
  663. void save_minor_area( chtype *buffer, int wid, int len, int row, int col )
  664. {
  665. int i;
  666. int j;
  667.  
  668.    wid--;
  669.    len--;
  670.    for (i=0; len >= 0; len--) {
  671.       for (j=wid; j >= 0; j--, i++)
  672.          buffer[i] = mvinch( row+len, col+j );
  673.    }
  674. }
  675.  
  676.  
  677. /*
  678.  * Name:    retore_minor_area
  679.  * Purpose: restore text and attribute under the pulled menu
  680.  * Date:    November 13, 1993
  681.  * Passed:  buffer: storage for text and attribute
  682.  *          wid: width of the pulled menu
  683.  *          len: length of pulled menu
  684.  *          row: starting row of pulled menu
  685.  *          col: starting column of pulled menu
  686.  * Notes:   use curses to set char and attr
  687.  */
  688. void restore_minor_area( chtype *buffer, int wid, int len, int row, int col )
  689. {
  690. int i;
  691. int j;
  692.  
  693.    wid--;
  694.    len--;
  695.    for (i=0; len >= 0; len--) {
  696.       for (j=wid; j >= 0; j--, i++)
  697.          mvaddch( row+len, col+j, buffer[i] );
  698.    }
  699.    refresh( );
  700. }
  701.  
  702.  
  703. #else
  704. /*
  705.  **********************************************************************
  706.  ******************************  PART 2  ******************************
  707.  **********************************************************************
  708.  *
  709.  * Calls to BIOS and writes to PC hardware.
  710.  */
  711.  
  712. #include <bios.h>               /* for direct BIOS keyboard input */
  713.  
  714.  
  715. /*
  716.  *   BIOS Data Areas
  717.  *
  718.  *   See:
  719.  *
  720.  *      IBM Corp., _Technical Reference:  Personal Computer AT_,
  721.  *      Boca Raton, Florida, 1984, IBM part no. 1502494,
  722.  *      pp 5-29 thru 5-32.
  723.  *
  724.  *  These addresses, variable names, types, and descriptions are directly
  725.  *   from the IBM AT Technical Reference manual, BIOS listing, copyright IBM.
  726.  *
  727.  *   Address  Name           Type   Description
  728.  *   0x0449   CRT_MODE       Byte   Current CRT mode
  729.  *   0x044a   CRT_COLS       Word   Number columns on screen
  730.  *   0x044c   CRT_LEN        Word   length of regen buffer, video buffer, bytes
  731.  *   0x044e   CRT_START      Word   Starting address of regen buffer
  732.  *   0x0450   CURSOR_POSN    Word   cursor for each of up to 8 pages.
  733.  *   0x0460   CURSOR_MODE    Word   current cursor mode setting.
  734.  *   0x0462   ACTIVE_PAGE    Byte   Current page
  735.  *   0x0463   ADDR_6845      Word   base address for active display card
  736.  *   0x0465   CRT_MODE_SET   Byte   current mode of display card
  737.  *   0x0466   CRT_PALETTE    Byte   overscan color for CGA, EGA, and VGA.
  738.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  739.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  740.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  741.  *   0x046c   timer_low      Word   Low word of timer count
  742.  *   0x046e   timer_high     Word   High word of timer count
  743.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  744.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  745.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  746.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  747.  *   0x0485   POINTS         Word   Height of character matrix
  748.  *   0x0487   INFO           Byte   EGA and VGA display data
  749.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  750.  *   0x0489   flags          Byte   Miscellaneous flags
  751.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  752.  *   0x048A   DCC            Byte   Display Combination Code
  753.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  754.  */
  755. void video_config( struct vcfg *cfg )
  756. {
  757. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  758.  
  759. struct LOWMEMVID
  760. {
  761.    char     vidmode;           /* 0x449 */
  762.    unsigned scrwid;            /* 0x44A */
  763.    unsigned scrlen;            /* 0x44C */
  764.    unsigned scroff;            /* 0x44E */
  765.    struct   LOCATE
  766.    {
  767.       unsigned char col;
  768.       unsigned char row;
  769.    } csrpos[8];                /* 0x450 */
  770.    struct   CURSIZE
  771.    {
  772.       unsigned char end;
  773.       unsigned char start;
  774.    } csrsize;                  /* 0x460 */
  775.    char      page;             /* 0x462 */
  776.    unsigned  addr_6845;        /* 0x463 */
  777.    char      crt_mode_set;     /* 0x465 */
  778.    char      crt_palette;      /* 0x466 */
  779.    char      system_stuff[29]; /* 0x467 */
  780.    unsigned char  rows;        /* 0x484 */
  781.    unsigned  points;           /* 0x485 */
  782.    char      ega_info;         /* 0x487 */
  783.    char      info_3;           /* 0x488 */
  784.    char      skip[13];         /* 0x489 */
  785.    char      kb_flag_3;        /* 0x496 */
  786. } vid;
  787. struct LOWMEMVID _far *pvid = &vid;
  788. #pragma pack( )    /* revert to previously defined pack pragma. */
  789.  
  790. union REGS in, out;
  791. unsigned char temp, active_display;
  792.  
  793.    /*
  794.     * Move system information into our video structure.
  795.     */
  796.    my_memmove( pvid, (void FAR *)0x00000449l, sizeof( vid ) );
  797.  
  798.    /*
  799.     * this next code was contributed by Jim Derr <jim.derr@spacebbs.com>
  800.     */
  801.    cfg->cols      = vid.scrwid;
  802.    cfg->regen_len = vid.scrlen;
  803.    cfg->rows      = vid.rows;
  804.  
  805.  
  806.    cfg->rescan = FALSE;
  807.    in.x.ax =  0x1a00;
  808.    int86( VIDEO_INT, &in, &out );
  809.    temp = out.h.al;
  810.    active_display = out.h.bl;
  811.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  812.       g_display.adapter = VGA;
  813.    else {
  814.       in.h.ah =  0x12;
  815.       in.h.bl =  0x10;
  816.       int86( VIDEO_INT, &in, &out );
  817.       if (out.h.bl != 0x10) {         /* EGA */
  818.          if (vid.ega_info & 0x08)
  819.             g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA;
  820.          else
  821.             g_display.adapter = EGA;
  822.       } else if (vid.addr_6845 == 0x3d4)
  823.          g_display.adapter = CGA;
  824.       else
  825.          g_display.adapter = MDA;
  826.    }
  827.  
  828.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  829.       if (g_display.adapter == CGA)
  830.          cfg->rescan = TRUE;
  831.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407;
  832.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607;
  833.    } else {
  834.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b;
  835.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c;
  836.    }
  837.  
  838.    cfg->mode = vid.vidmode;
  839.    if (vid.addr_6845 == 0x3D4) {
  840.       cfg->color = TRUE;
  841.       cfg->videomem = (void FAR *)0xb8000000l;
  842.    } else {
  843.       cfg->color = FALSE;
  844.       cfg->videomem = (void FAR *)0xb0000000l;
  845.    }
  846.  
  847.    /*
  848.     * let save the overscan color
  849.     */
  850.    g_display.old_overscan = vid.crt_palette;
  851.  
  852.  
  853.    /*
  854.     * Get keyboard type.  Since there is no interrupt that determines
  855.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  856.     * This method is not always foolproof on clones.
  857.     */
  858.    if ((vid.kb_flag_3 & 0x10) != 0)
  859.       mode.enh_kbd = TRUE;
  860.    else
  861.       mode.enh_kbd = FALSE;
  862.    if (mode.enh_kbd == FALSE)
  863.       simulate_enh_kbd( 1 );
  864. }
  865.  
  866.  
  867. /*
  868.  * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and
  869.  * modified extensively by Frank Davis.
  870.  *
  871.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  872.  * problem when getch() is used in a program.  For example, instead of returning
  873.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  874.  * of using getch(), I use the following function ..."
  875.  *
  876.  * Tom, thanks for the info and solution.  I'm sure your function will be
  877.  * be appreciated by everyone with ANSI key defs, Frank.
  878.  */
  879.  
  880. /*
  881.  * Name:    getkey
  882.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  883.  *          redefined keys)
  884.  * Date:    July 2, 1991
  885.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  886.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  887.  * Passed:  None
  888.  * Notes:   Uses the BIOS to read the next keyboard character.  Service 0x00
  889.  *           is the XT keyboard read.  Service 0x10 is the extended keyboard
  890.  *           read.  Test for a bunch of special cases.  Allow the user to enter
  891.  *           any ASCII or Extended ASCII code as a normal text characters.
  892.  *
  893.  *          Control @ is defined as 0.  we need to do a special test
  894.  *           for this key, otherwise it's interpretted as an Alt key.  It's
  895.  *           the only "regular" Control key that returns 0 in AL and the scan
  896.  *           byte in AH.  The "regular" Control keys are those in the range
  897.  *           0-31 and they return the Control character in AL and the scan
  898.  *           code in AH.  All of the Alt + keys return 0 in AL and
  899.  *           the scan code in ah.
  900.  *
  901.  *          This function was written for US keyboards.  It may have to be
  902.  *           modified for other keyboards, eg. Belgium, Canada, Czech,
  903.  *           Slovak, Denmark, France, Germany, etc...
  904.  *
  905.  *          if Ctrl-Break is pressed, it returns 0xffff as the key pressed.
  906.  *           let's set it to CONTROL_BREAK == 269 and do nothing.
  907.  */
  908. int getkey( void )
  909. {
  910. unsigned key, num_lock, control, shift;
  911. register scan;
  912. register unsigned lo;
  913.  
  914. /*
  915.  * this code is used during testing to check the amount of memory
  916.  *    in the near heap.
  917.  *
  918.  * char temp[MAX_COLS+2];
  919.  *
  920.  * ultoa( _memavl( ), temp, 10 );
  921.  * s_output( "h=       ", g_display.mode_line, 37, g_display.mode_color );
  922.  * s_output( temp, g_display.mode_line, 39, g_display.mode_color );
  923.  */
  924.  
  925.    /*
  926.     * lets spin on waitkey until the user presses a key.  waitkey polls
  927.     *  the keyboard and returns 0 when a key is waiting.
  928.     */
  929.    while (waitkey( mode.enh_kbd ));
  930.  
  931.    /*
  932.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  933.     *   and the ascii key code in al, lo part of key.  If the character was
  934.     *   entered via ALT-xxx, the scan code, hi part of key, is 0.
  935.     */
  936.    if (mode.enh_kbd) {
  937.       key = _bios_keybrd( 0x10 );
  938.       lo  = _bios_keybrd( 0x12 );
  939.  
  940.       /*
  941.        * couple of special cases:
  942.        *   on the numeric keypad, some keys return 0xe0 in the lo byte.
  943.        *   1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0.
  944.        *   we need to let this get thru as an Extended ASCII char.  2) although
  945.        *   we could make the cursor pad keys do different functions than the
  946.        *   numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero
  947.        *   and forget about support for those keys.
  948.        */
  949.       if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0)
  950.          key = key & 0xff00;
  951.    } else {
  952.       key = _bios_keybrd( 0 );
  953.       lo  = _bios_keybrd( 2 );
  954.    }
  955.    num_lock = lo & 0x20;
  956.    control  = lo & 0x04;
  957.    shift    = lo & 0x03;
  958.    scan = (key & 0xff00) >> 8;
  959.    lo = key & 0X00FF;
  960.  
  961.    if (lo == 0) {
  962.       /*
  963.        * special case for Control @, which is defined as 0 or NULL.
  964.        */
  965.       if (scan == 3)
  966.          lo = 430;
  967.  
  968.       /*
  969.        * when first byte is 0, map it above 256, so that we can
  970.        *  let ALT-xxx keys map to their 'natural' place.  In
  971.        *  otherwords, use 0-255 as normal text characters and
  972.        *  those >= 256 are function keys.
  973.        */
  974.       else
  975.          lo = scan | 0x100;
  976.  
  977.    /*
  978.     * now test for Control-Break.  let's set this to do nothing in the
  979.     *  editor.  manually map Control-Break to 269 - DO NOT assign
  980.     *  any function to 269.
  981.     */
  982.    } else if (key == 0xffff)
  983.       lo = CONTROL_BREAK;
  984.  
  985.  
  986.    /*
  987.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  988.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  989.     * 0x7f character, then they can enter it via ALT+xxx.
  990.     */
  991.    if (scan == 14 && lo == 0x7f)
  992.       lo = 8;
  993.  
  994.    /*
  995.     * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad
  996.     *  ENTER and / keys are read through the BIOS interrupt 16h, only E0h
  997.     *  is seen since the interrupt only gives one-byte scan codes."
  998.     */
  999.    else if (scan == 0xe0) {
  1000.       /*
  1001.        * plain Grey Enter
  1002.        */
  1003.       if (lo == 13 && !shift)
  1004.          lo = 285;
  1005.       /*
  1006.        * shift Grey Enter
  1007.        */
  1008.       else if (lo == 13)
  1009.          lo = 298;
  1010.       /*
  1011.        * control Grey Enter
  1012.        */
  1013.       else if (lo == 10)
  1014.          lo = 299;
  1015.    }
  1016.  
  1017.    /*
  1018.     *  let's massage all of the control key combinations.
  1019.     */
  1020.    if (lo < 32) {
  1021.  
  1022.       /*
  1023.        * My machine at home is sorta weird.  On every machine that I've
  1024.        *  tested at the awffice, the ALT-xxx combination returns 0 for the
  1025.        *  scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  1026.        *  as the scan code?!?!?  I added the next two lines for my machine at
  1027.        *  home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  1028.        *  when they wrote my bios?
  1029.        */
  1030.       if (scan > 0x80)
  1031.          scan = 0;
  1032.  
  1033.       /*
  1034.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  1035.        *  key is 1.  Map this to a different index into the key function
  1036.        *  array just in case someone wants to define ESC or ^[ to different
  1037.        *  functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  1038.        */
  1039.       else if (scan == 1) {
  1040.          if (shift)
  1041.             lo = 259;
  1042.          else if (control)
  1043.             lo = 260;
  1044.          else
  1045.             lo = 258;
  1046.       }
  1047.  
  1048.       /*
  1049.        * Scan code for Enter = 28.  Separate the various Enter keys.
  1050.        */
  1051.       else if (scan == 28) {
  1052.          if (shift)
  1053.             lo = 263;
  1054.          else if (control)
  1055.             lo = 264;
  1056.          else
  1057.             lo = 262;
  1058.       }
  1059.  
  1060.       /*
  1061.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  1062.        */
  1063.       else if (scan == 14) {
  1064.          if (shift)
  1065.             lo = 266;
  1066.          else if (control)
  1067.             lo = 267;
  1068.          else
  1069.             lo = 265;
  1070.       }
  1071.  
  1072.       /*
  1073.        * Scan code for Tab = 15.  Separate the tab key.
  1074.        */
  1075.       else if (scan == 15) {
  1076.          lo = 268;
  1077.       }
  1078.  
  1079.       /*
  1080.        * if scan code is not 0, then a Control key was pressed.  Map
  1081.        *  those keys to the WordStar commands.
  1082.        */
  1083.       else if (scan > 0)
  1084.          lo += 430;
  1085.  
  1086.    } else if (!num_lock) {
  1087.       switch (scan) {
  1088.          /*
  1089.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  1090.           *  to the scroll line up function.
  1091.           */
  1092.          case 74 :
  1093.             lo = 423;
  1094.             break;
  1095.  
  1096.          /*
  1097.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  1098.           *  to the scroll line down function.  if shift grey + then stationary
  1099.           *  scroll down.
  1100.           */
  1101.          case 78 :
  1102.             lo = 424;
  1103.             break;
  1104.       }
  1105.    }
  1106.  
  1107.  
  1108.    /*
  1109.     * let's set up for the Shift+Alt and Control+Alt keys.
  1110.     *  With these key combinations, we can do the International keyboard
  1111.     *  stuff, see the Microsoft MS DOS 5.0 manual pages 623-637.
  1112.     */
  1113.    if (lo > 256 && (shift || control)) {
  1114.  
  1115.       /*
  1116.        * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed.
  1117.        *  this is not part of the International keyboard stuff, just a way
  1118.        *  to assign the horizontal scroll left and right funcs to cursor keys.
  1119.        */
  1120.       if (shift) {
  1121.          if (lo >= 371 && lo <= 374)
  1122.             lo += 55;
  1123.  
  1124.          /*
  1125.           * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+
  1126.           */
  1127.          else if (lo >= 376 && lo <= 387)
  1128.             lo += 86;
  1129.  
  1130.          /*
  1131.           * internation keyboard stuff
  1132.           */
  1133.          else if (lo >= 272 && lo <= 309)
  1134.             lo += 202;
  1135.       }
  1136.    }
  1137.  
  1138.    /*
  1139.     * map the enter key to line feed.
  1140.     */
  1141.    if (lo == 10  &&  scan != 0)
  1142.       lo = 425;
  1143.    return( lo );
  1144. }
  1145.  
  1146.  
  1147. /*
  1148.  * Name:    waitkey
  1149.  * Purpose: call the BIOS keyboard status subfunction
  1150.  * Date:    October 31, 1992
  1151.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  1152.  * Returns: 1 if no key ready, 0 if key is waiting
  1153.  * Notes:   lets get the keyboard status so we can spin on this function until
  1154.  *           the user presses a key.  some OS replacements for DOS want
  1155.  *           application programs to poll the keyboard instead of rudely
  1156.  *           sitting on the BIOS read key function.
  1157.  */
  1158. int  waitkey( int enh_keyboard )
  1159. {
  1160.    return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 );
  1161. }
  1162.  
  1163.  
  1164. /*
  1165.  * Name:    flush_keyboard
  1166.  * Purpose: flush keys from the keyboard buffer
  1167.  * Date:    June 5, 1993
  1168.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  1169.  * Returns: 1 if no key ready, 0 if key is waiting
  1170.  * Notes:   lets get the keyboard status so we can spin on this function until
  1171.  *           the user presses a key.  some OS replacements for DOS want
  1172.  *           application programs to poll the keyboard instead of rudely
  1173.  *           sitting on the BIOS read key function.
  1174.  */
  1175. void flush_keyboard( void )
  1176. {
  1177.    if (mode.enh_kbd) {
  1178.       while (!waitkey( mode.enh_kbd ))
  1179.          _bios_keybrd( 0x10 );
  1180.    } else {
  1181.       while (!waitkey( mode.enh_kbd ))
  1182.          _bios_keybrd( 0 );
  1183.    }
  1184. }
  1185.  
  1186.  
  1187. /*********************************************/
  1188. /*                                           */
  1189. /*  3) video output routines, PC specific    */
  1190. /*                                           */
  1191. /*********************************************/
  1192.  
  1193.  
  1194. /*
  1195.  * Name:    xygoto
  1196.  * Purpose: To move the cursor to the required column and line.
  1197.  * Date:    September 28, 1991
  1198.  * Passed:  col:    desired column (0 up to max)
  1199.  *          line:   desired line (0 up to max)
  1200.  * Notes;   use standard BIOS video interrupt 0x10 to set the set.
  1201.  */
  1202. void xygoto( int col, int line )
  1203. {
  1204. union REGS inregs, outregs;
  1205.  
  1206.    inregs.h.ah = 2;
  1207.    inregs.h.bh = 0;
  1208.    inregs.h.dh = (unsigned char)line;
  1209.    inregs.h.dl = (unsigned char)col;
  1210.    int86( 0x10, &inregs, &outregs );
  1211. }
  1212.  
  1213.  
  1214. /*
  1215.  * Name:    update_line
  1216.  * Purpose: Display the current line in window
  1217.  * Date:    June 5, 1991
  1218.  * Passed:  window:  pointer to current window
  1219.  * Notes:   Show string starting at column zero and if needed blank rest
  1220.  *           of line.  Put max_col in cx and count down.  When we run into
  1221.  *           len, cx contains number of columns to blank out.  Use the
  1222.  *           fast 'rep stosw' to clear the end of line.
  1223.  *          The C routine was probably fast enough, but let's do some
  1224.  *           assembly because it's so fun.
  1225.  *          To handle line lengths longer than 255 characters,
  1226.  *           block begin and end columns were changed from real
  1227.  *           to virtual columns in this display routine.
  1228.  */
  1229. void update_line( TDE_WIN *window )
  1230. {
  1231. text_ptr text;      /* current character of orig begin considered */
  1232. char FAR *screen_ptr;
  1233. int  off;
  1234. int  attr;
  1235. int  line;
  1236. int  col;
  1237. int  bcol;
  1238. int  bc;
  1239. int  ec;
  1240. int  normal;
  1241. int  block;
  1242. int  max_col;
  1243. int  block_line;
  1244. int  len;
  1245. int  show_eol;
  1246. int  c;
  1247. long rline;
  1248. file_infos *file;
  1249.  
  1250.    if (window->rline > window->file_info->length || window->ll->len == EOF
  1251.              || !g_status.screen_display)
  1252.       return;
  1253.    file = window->file_info;
  1254.    max_col = window->end_col + 1 - window->start_col;
  1255.    line = window->cline;
  1256.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  1257.    block = g_display.block_color;
  1258.    show_eol = mode.show_eol;
  1259.  
  1260.    /*
  1261.     * set the screen pointer to physical screen memory.
  1262.     *       160 = 80 chars + 80 attr  for each line
  1263.     */
  1264.    screen_ptr = g_display.display_address;
  1265.  
  1266.    /*
  1267.     * this next suggestion is part of chen's screen changes.
  1268.     *
  1269.     * off = line * 160 + window->start_col * 2;
  1270.     *
  1271.     *              change to:
  1272.     */
  1273.    off = line * (g_display.ncols*2) + window->start_col * 2;
  1274.  
  1275.    /*
  1276.     * figure which line to display.
  1277.     * actually, we could be displaying any line in any file.  we display
  1278.     *  the line_buffer only if window->ll == g_status.buff_node
  1279.     *  and window->ll-line has been copied to g_status.line_buff.
  1280.     */
  1281.    text = window->ll->line;
  1282.    len  = window->ll->len;
  1283.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  1284.       text = (text_ptr)g_status.line_buff;
  1285.       len  = g_status.line_buff_len;
  1286.    }
  1287.    if (mode.inflate_tabs)
  1288.       text = tabout( text, &len );
  1289.  
  1290.    /*
  1291.     * lets look at the base column.  if the line to display is shorter
  1292.     *  than the base column, then set text to eol and we can't see the
  1293.     *  eol either.
  1294.     */
  1295.    bc = window->bcol;
  1296.    if (bc > 0) {
  1297.       if (text == NULL) {
  1298.          show_eol = FALSE;
  1299.          len = 0;
  1300.       } else {
  1301.          if ((col = len) < bc) {
  1302.             bc = col;
  1303.             show_eol = FALSE;
  1304.          }
  1305.          text += bc;
  1306.          len  -= bc;
  1307.       }
  1308.    }
  1309.  
  1310.    /*
  1311.     * for display purposes, set the line length to screen width if line
  1312.     *  is longer than screen.  our assembly routine uses bytes and the
  1313.     *  the line length can be longer than a byte.
  1314.     */
  1315.    if (len > max_col)
  1316.       len = max_col;
  1317.  
  1318.    bcol = window->bcol;
  1319.    rline = window->rline;
  1320.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  1321.       block_line = TRUE;
  1322.    else
  1323.       block_line = FALSE;
  1324.  
  1325.    /*
  1326.     * do this if 1) a box block is marked, or 2) a stream block begins
  1327.     *  and ends on the same line.
  1328.     */
  1329.    if (block_line == TRUE && (file->block_type == BOX ||
  1330.          (file->block_type == STREAM &&
  1331.          rline == file->block_br && rline == file->block_er))) {
  1332.  
  1333.       /*
  1334.        * start with the bc and ec equal to physical block marker.
  1335.        */
  1336.       bc = file->block_bc;
  1337.       ec = file->block_ec;
  1338.       if (ec < bcol || bc >= bcol + max_col)
  1339.          /*
  1340.           * we can't see block if ending column is less than the base col or
  1341.           *  the beginning column is greater than max_col.
  1342.           */
  1343.          ec = bc = max_col + 1;
  1344.       else if (ec < bcol + max_col) {
  1345.          /*
  1346.           * if the ec is less than the max column, make ec relative to
  1347.           *  base column then figure the bc.
  1348.           */
  1349.          ec = ec - bcol;
  1350.          if (bc < bcol)
  1351.             bc = 0;
  1352.          else
  1353.             bc = bc - bcol;
  1354.       } else if (bc < bcol + max_col) {
  1355.          /*
  1356.           * if the bc is less than the max column, make bc relative to
  1357.           *  base column then figure the ec.
  1358.           */
  1359.          bc = bc - bcol;
  1360.          if (ec > bcol + max_col)
  1361.             ec = max_col;
  1362.          else
  1363.             ec = ec - bcol;
  1364.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  1365.          /*
  1366.           * if the block is wider than the screen, make bc start at the
  1367.           *  logical begin and make ec end at the logical end of the
  1368.           *  window.
  1369.           */
  1370.          bc = 0;
  1371.          ec = max_col;
  1372.       }
  1373.  
  1374.  
  1375.    ASSEMBLE {
  1376.         /*
  1377.         ; Register strategy:
  1378.         ;   bx == beginning column
  1379.         ;      == ending column
  1380.         ;   dl == normal text attribute
  1381.         ;   dh == block attribute
  1382.         ;   cx == current virtual column
  1383.         ;      == maximum columns in window
  1384.         ;   ES:DI == screen pointer (destination)
  1385.         ;   DS:SI == text pointer (source)
  1386.         ;   [bp+show_eol]  == access for local C variable
  1387.         */
  1388.  
  1389.  
  1390.         push    ds                      /* MUST save ds - push it on stack */
  1391.         push    si                      /* save si on stack */
  1392.         push    di                      /* save di on stack */
  1393.  
  1394. /*
  1395. ;
  1396. ; set up local register variables
  1397. ;
  1398. */
  1399.         mov     bx, WORD PTR bc         /* get beginning column */
  1400.         mov     ax, WORD PTR normal     /* get normal attribute */
  1401.         mov     dl, al                  /* keep it in dl */
  1402.         mov     ax, WORD PTR block      /* get block attribute */
  1403.         mov     dh, al                  /* keep it in dh */
  1404.         xor     cx, cx                  /* col = 0, keep col in cl */
  1405. /*
  1406. ;
  1407. ; load screen and text pointer
  1408. ;
  1409. */
  1410.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1411.         add     di, WORD PTR off                /* add offset of line */
  1412.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1413.         mov     es, ax
  1414.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1415.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1416.         mov     ds, ax                  /* move segment of text in ds */
  1417.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  1418.         jne     not_null                /* no, output string */
  1419.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  1420.         je      dspl_eol                /* yes, clear end of line */
  1421.    }
  1422. not_null:
  1423.  
  1424.    ASSEMBLE {
  1425.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1426.         jge     getout                  /* yes, thru with line */
  1427.         cmp     cx, Word Ptr len        /* is col == len? */
  1428.         je      dspl_eol                /* yes, must check block past eol */
  1429.    }
  1430. top:
  1431.  
  1432.    ASSEMBLE {
  1433.         lodsb                   /* get next char in string */
  1434.         mov     ah, dl          /* assume normal attribute */
  1435.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1436.         jl      ch_out1         /* yes, show char and normal attribute */
  1437.         cmp     cx, Word Ptr ec /* is col > ec? (greater than ending col) */
  1438.         jg      ch_out1         /* yes, show char and normal attribute */
  1439.         mov     ah, dh          /* must be in a block - block attribute */
  1440.    }
  1441. ch_out1:
  1442.  
  1443.    ASSEMBLE {
  1444.         stosw                   /* now show char on screen w/ attribute */
  1445.         inc     cx              /* ++col */
  1446.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1447.         jge     getout          /* yes, thru with line */
  1448.         cmp     cx, Word Ptr len        /* is col == len? */
  1449.         jl      top             /* yes, must check block past eol */
  1450.    }
  1451. dspl_eol:
  1452.  
  1453.    ASSEMBLE {
  1454.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1455.         je      block_eol       /* show_eol flag is FALSE, blank line */
  1456.         mov     al, EOL_CHAR    /* load some eol indicator */
  1457.         mov     ah, dl          /* assume normal attribute */
  1458.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1459.         jl      ch_out2         /* yes, show char and normal attribute */
  1460.         cmp     cx, Word Ptr ec /* is col > ec? (greater than ending col) */
  1461.         jg      ch_out2         /* yes, show char and normal attribute */
  1462.         mov     ah, dh          /* must be in a block - show block attribute */
  1463.    }
  1464. ch_out2:
  1465.  
  1466.    ASSEMBLE {
  1467.         stosw                   /* write eol and attribute to screen */
  1468.         inc     cx              /* ++col */
  1469.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1470.         je      getout          /* yes, we're done */
  1471.    }
  1472. block_eol:
  1473.  
  1474.    ASSEMBLE {
  1475.         mov     al, ' '         /* clear rest of line w/ spaces */
  1476.    }
  1477. b1:
  1478.  
  1479.    ASSEMBLE {
  1480.         mov     ah, dl          /* assume normal attribute */
  1481.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1482.         jl      ch_out3         /* yes, show char and normal attribute */
  1483.         cmp     cx, Word Ptr ec /* is col > ec? (greater than ending col) */
  1484.         jg      ch_out3         /* yes, show char and normal attribute */
  1485.         mov     ah, dh          /* must be in a block - show block attribute */
  1486.    }
  1487. ch_out3:
  1488.  
  1489.    ASSEMBLE {
  1490.         stosw                   /* write blank and attribute to screen */
  1491.         inc     cx              /* ++col */
  1492.         cmp     cx, Word Ptr max_col         /* is col == max_col? */
  1493.         jl      b1              /* while less output block */
  1494.    }
  1495. getout:
  1496.  
  1497.    ASSEMBLE {
  1498.         pop     di
  1499.         pop     si
  1500.         pop     ds
  1501.       }
  1502.  
  1503. /*
  1504.       screen_ptr += off;
  1505.       bcol = window->start_col;
  1506.       for (col=0; col < max_col; col++, bcol++) {
  1507.          attr = normal;
  1508.          if (col >= bc && col <= ec)
  1509.             attr = block;
  1510.          if (col < len)
  1511.             c = *text++;
  1512.          else if (col == len && show_eol)
  1513.             c = EOL_CHAR;
  1514.          else
  1515.             c = ' ';
  1516.          *screen_ptr++ = c;
  1517.          *screen_ptr++ = attr;
  1518.  
  1519.          c_output( c, bcol, line, attr );
  1520.       }
  1521. */
  1522.    } else if (block_line == TRUE && file->block_type == STREAM &&
  1523.               (rline == file->block_br || rline == file->block_er)) {
  1524.       if (rline == file->block_br)
  1525.          bc = file->block_bc;
  1526.       else {
  1527.          bc = file->block_ec + 1;
  1528.          ec = normal;
  1529.          normal = block;
  1530.          block = ec;
  1531.       }
  1532.       if (bc < bcol)
  1533.          bc = 0;
  1534.       else if (bc < bcol + max_col)
  1535.          bc = bc - bcol;
  1536.       else
  1537.          bc = max_col + 1;
  1538.  
  1539.  
  1540.    ASSEMBLE {
  1541.         /*
  1542.         ; Register strategy:
  1543.         ;   bx == beginning column
  1544.         ;      == relative line length
  1545.         ;   dl == normal text attribute
  1546.         ;   dh == block attribute
  1547.         ;   cx == current virtual column
  1548.         ;      == maximum columns in window
  1549.         ;   ES:DI == screen pointer (destination)
  1550.         ;   DS:SI == text pointer (source)
  1551.         ;   [bp+show_eol]  == access for local C variable
  1552.         */
  1553.  
  1554.         push    ds                      /* MUST save ds - push it on stack */
  1555.         push    si                      /* save si on stack */
  1556.         push    di                      /* save di on stack */
  1557.  
  1558. /*
  1559. ;
  1560. ; set up local register variables
  1561. ;
  1562. */
  1563.         mov     bx, WORD PTR bc         /* get beginning column */
  1564.         mov     ax, WORD PTR normal     /* get normal attribute */
  1565.         mov     dl, al                  /* keep it in dl */
  1566.         mov     ax, WORD PTR block      /* get block attribute */
  1567.         mov     dh, al                  /* keep it in dh */
  1568.         xor     cx, cx                  /* col = 0, keep col in cl */
  1569. /*
  1570. ;
  1571. ; load screen and text pointer
  1572. ;
  1573. */
  1574.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1575.         add     di, WORD PTR off                /* add offset of line */
  1576.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1577.         mov     es, ax
  1578.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1579.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1580.         mov     ds, ax                  /* move segment of text in ds */
  1581.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  1582.         jne     nott_null               /* no, output string */
  1583.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  1584.         je      ddspl_eol               /* yes, clear end of line */
  1585.    }
  1586. nott_null:
  1587.  
  1588.    ASSEMBLE {
  1589.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1590.         je      ggetout         /* yes, thru with line */
  1591.         cmp     cx, Word Ptr len        /* is col == len? */
  1592.         je      ddspl_eol       /* yes, check eol display */
  1593.    }
  1594. ttop:
  1595.  
  1596.    ASSEMBLE {
  1597.         lodsb                   /* get next char in string */
  1598.         mov     ah, dl          /* assume normal attribute */
  1599.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1600.         jl      str_out1        /* yes, show char and normal attribute */
  1601.         mov     ah, dh          /* must be in a block - show block attribute */
  1602.    }
  1603. str_out1:
  1604.  
  1605.    ASSEMBLE {
  1606.         stosw                   /* else show char on screen */
  1607.         inc     cx              /* ++col */
  1608.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1609.         je      ggetout         /* yes, thru with line */
  1610.         cmp     cx, Word Ptr len        /* is col == len? */
  1611.         jl      ttop            /* yes, check eol display */
  1612.    }
  1613. ddspl_eol:
  1614.  
  1615.    ASSEMBLE {
  1616.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1617.         je      stream_eol      /* show_eol flag is FALSE, blank line */
  1618.         mov     al, EOL_CHAR    /* load some eol indicator */
  1619.         mov     ah, dl          /* assume normal attribute */
  1620.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1621.         jl      str_out2        /* yes, show char and normal attribute */
  1622.         mov     ah, dh          /* must be in a block - show block attribute */
  1623.    }
  1624. str_out2:
  1625.  
  1626.    ASSEMBLE {
  1627.         stosw                   /* write blank and attribute to screen */
  1628.         inc     cx              /* ++col */
  1629.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1630.         jge     ggetout         /* yes, we're done */
  1631.    }
  1632. stream_eol:
  1633.  
  1634.    ASSEMBLE {
  1635.         mov     al, ' '         /* clear rest of line w/ spaces */
  1636.    }
  1637. c1:
  1638.  
  1639.    ASSEMBLE {
  1640.         mov     ah, dl          /* assume normal attribute */
  1641.         cmp     cx, bx          /* is col < bc? (less than beginning col) */
  1642.         jl      str_out3        /* yes, show char and normal attribute */
  1643.         mov     ah, dh          /* must be in a block - show block attribute */
  1644.    }
  1645. str_out3:
  1646.  
  1647.    ASSEMBLE {
  1648.         stosw                   /* write blank and attribute to screen */
  1649.         inc     cx              /* ++col */
  1650.         cmp     cx, Word Ptr max_col    /* is col == max_col? */
  1651.         jl      c1              /* while less output block */
  1652.    }
  1653. ggetout:
  1654.  
  1655.    ASSEMBLE {
  1656.         pop     di
  1657.         pop     si
  1658.         pop     ds
  1659.       }
  1660.  
  1661. /*
  1662.       screen_ptr += off;
  1663.       bcol = window->start_col;
  1664.       for (col=0; col < max_col; col++, bcol++) {
  1665.          attr = normal;
  1666.          if (col >= bc && col <= ec)
  1667.             attr = block;
  1668.          if (col < len)
  1669.             c = *text++;
  1670.          else if (col == len && show_eol)
  1671.             c = EOL_CHAR;
  1672.          else
  1673.             c = ' ';
  1674.          *screen_ptr++ = c;
  1675.          *screen_ptr++ = attr;
  1676.          c_output( c, bcol, line, attr );
  1677.       }
  1678. */
  1679.    } else {
  1680.       if (block_line)
  1681.          attr = block;
  1682.       else
  1683.          attr = normal;
  1684.  
  1685.       assert( len >= 0 );
  1686.       assert( len <= g_display.ncols );
  1687.  
  1688.    ASSEMBLE {
  1689.         /*
  1690.         ; Register strategy:
  1691.         ;   bl == normal text attribute
  1692.         ;      == relative line length
  1693.         ;   cx == current virtual column
  1694.         ;   dx == maximum columns in window
  1695.         ;   ES:DI == screen pointer (destination)
  1696.         ;   DS:SI == text pointer (source)
  1697.         ;   [bp+show_eol]  == access for local C variable
  1698.         */
  1699.  
  1700.         push    ds              /* MUST save ds - push it on stack */
  1701.         push    di              /* save di on stack */
  1702.         push    si              /* save si on stack */
  1703.  
  1704.  
  1705.         mov     bx, WORD PTR attr               /* keep attribute in bl */
  1706.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1707.         xor     cx, cx                          /* zero out cx (col) */
  1708.         mov     di, WORD PTR screen_ptr         /* load OFFST of screen ptr */
  1709.         add     di, WORD PTR off                /* add offset of line */
  1710.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1711.         mov     es, ax
  1712.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1713.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1714.         mov     ds, ax                  /* move segment of text in ds */
  1715.         cmp     si, 0                   /* is offset of pointer == NULL? */
  1716.         jne     nnot_null               /* no, output string */
  1717.         cmp     ax, 0                   /* is segment of pointer == NULL? */
  1718.         je      normeol                 /* yes, then clear rest of line */
  1719.    }
  1720. nnot_null:
  1721.  
  1722.    ASSEMBLE {
  1723.         mov     ah, bl          /* get attribute */
  1724.         cmp     cx, dx          /* compare count with max columns */
  1725.         jge     getoutt         /* yes, thru with line */
  1726.         cmp     cx, Word Ptr len        /* compare count with len */
  1727.         je      normeol         /* yes, clear end of line */
  1728.    }
  1729. topp:
  1730.  
  1731.    ASSEMBLE {
  1732.         lodsb                   /* get next char in string */
  1733.         stosw                   /* else show char on screen */
  1734.         inc     cx              /* ++col, count up to max_column */
  1735.         cmp     cx, dx          /* compare count with max columns */
  1736.         jge     getoutt         /* yes, thru with line */
  1737.         cmp     cx, Word Ptr len        /* compare count with len */
  1738.         jl      topp            /* yes, clear end of line */
  1739.    }
  1740. normeol:
  1741.  
  1742.    ASSEMBLE {
  1743.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1744.         je      clreol          /* show_eol flag is FALSE, blank line */
  1745.         mov     al, EOL_CHAR    /* load some eol indicator */
  1746.         mov     ah, bl          /* assume normal attribute */
  1747.         stosw                   /* write blank and attribute to screen */
  1748.         inc     cx              /* ++col */
  1749.         cmp     cx, dx          /* is col == max_col? */
  1750.         jge     getoutt         /* yes, we're done */
  1751.    }
  1752. clreol:
  1753.  
  1754.    ASSEMBLE {
  1755.         mov     ah, bl          /* get attribute */
  1756.         mov     al, ' '         /* clear eol with ' ' */
  1757.         sub     dx, cx          /* find number of columns left */
  1758.         mov     cx, dx          /* put number of column left in cl */
  1759.         rep     stosw           /* count is in cx - set rest of line to ' ' */
  1760.    }
  1761. getoutt:
  1762.  
  1763.    ASSEMBLE {
  1764.         pop     si
  1765.         pop     di
  1766.         pop     ds
  1767.       }
  1768.  
  1769. /*
  1770.       screen_ptr += off;
  1771.       bcol = window->start_col;
  1772.       for (col=0; col < max_col; col++, bcol++) {
  1773.          if (col < len)
  1774.             c = *text++;
  1775.          else if (col == len && show_eol)
  1776.             c = EOL_CHAR;
  1777.          else
  1778.             c = ' ';
  1779.          *screen_ptr++ = c;
  1780.          *screen_ptr++ = attr;
  1781.          c_output( c, bcol, line, attr );
  1782.       }
  1783. */
  1784.    }
  1785. }
  1786.  
  1787.  
  1788. /*
  1789.  * Name:    c_output
  1790.  * Purpose: Output one character on prompt lines
  1791.  * Date:    June 5, 1991
  1792.  * Passed:  c:     character to output to screen
  1793.  *          col:   col to display character
  1794.  *          line:  line number to display character
  1795.  *          attr:  attribute of character
  1796.  * Returns: none
  1797.  */
  1798. void c_output( int c, int col, int line, int attr )
  1799. {
  1800. void FAR *screen_ptr;
  1801. int  off;
  1802.  
  1803.    screen_ptr = (void FAR *)g_display.display_address;
  1804.  
  1805.    /*
  1806.     * this next suggestion is part of chen's screen changes.
  1807.     *
  1808.     * off = line * 160 + col * 2;
  1809.     *
  1810.     *              change to:
  1811.     */
  1812.    off = line * (g_display.ncols*2) + col * 2;
  1813.  
  1814.    ASSEMBLE {
  1815.         mov     bx, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1816.         add     bx, WORD PTR off                /* add offset of line:col */
  1817.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1818.         mov     es, ax
  1819.         mov     cx, WORD PTR attr       /* get attribute */
  1820.         mov     ah, cl                  /* put in ah */
  1821.         mov     cx, WORD PTR c          /* get character */
  1822.         mov     al, cl                  /* put in al */
  1823.         mov     WORD PTR es:[bx], ax    /* show char on screen */
  1824.    }
  1825.  
  1826. /*
  1827.     * this next suggestion is part of chen's screen changes.
  1828.     *
  1829.     * screen_ptr = g_display.display_address + line * 160 + col * 2;
  1830.     *
  1831.     *              change to:
  1832.     *
  1833.    screen_ptr = g_display.display_address + line * (g_display.ncols*2) + col * 2;
  1834.    *screen_ptr++ = c;
  1835.    *screen_ptr = attr;
  1836. */
  1837. }
  1838.  
  1839.  
  1840. /*
  1841.  * Name:    s_output
  1842.  * Purpose: To output a string
  1843.  * Date:    June 5, 1991
  1844.  * Passed:  s:     string to output
  1845.  *          line:  line to display
  1846.  *          col:   column to begin display
  1847.  *          attr:  color to display string
  1848.  * Notes:   This function is used to output most strings not part of file text.
  1849.  */
  1850. void s_output( char FAR *s, int line, int col, int attr )
  1851. {
  1852. void FAR *screen_ptr;
  1853. int  off;
  1854. int  max_col;
  1855.  
  1856.    max_col = g_display.ncols;
  1857.    screen_ptr = (void FAR *)g_display.display_address;
  1858.    /*
  1859.     * this next suggestion is part of chen's screen changes.
  1860.     *
  1861.     * off = line * 160 + col * 2;
  1862.     *
  1863.     *              change to:
  1864.     */
  1865.    off = line * (g_display.ncols*2) + col * 2;
  1866.  
  1867.    ASSEMBLE {
  1868.         push    ds              /* save ds on stack */
  1869.         push    di              /* save di on stack */
  1870.         push    si              /* save si on stack */
  1871.  
  1872.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1873.         mov     cx, WORD PTR col                /* put cols in cx */
  1874.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1875.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1876.         add     di, WORD PTR off                /* add offset of line:col */
  1877.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1878.         mov     es, ax
  1879.         mov     si, WORD PTR s  /* load offset of string ptr */
  1880.         or      si, si          /* is it == NULL? */
  1881.         je      getout          /* yes, no output needed */
  1882.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  1883.         or      ax, ax          /* is pointer == NULL? */
  1884.         je      getout          /* yes, no output needed */
  1885.         mov     ds, ax          /* load segment of text in ds */
  1886.         mov     ah, bl          /* put attribute in AH */
  1887.    }
  1888. top:
  1889.  
  1890.    ASSEMBLE {
  1891.         cmp     cx, dx          /* col < max_cols? */
  1892.         jge     getout          /* no, thru with line */
  1893.         lodsb                   /* get next char in string - put in al */
  1894.         or      al, al          /* is it '\0' */
  1895.         je      getout          /* yes, end of string */
  1896.         cmp     al, 0x0a        /* is it '\n'? */
  1897.         je      getout          /* yes, end of string */
  1898.         stosw                   /* else show attr + char on screen (ah + al) */
  1899.         inc     cx              /* col++ */
  1900.         jmp     SHORT top       /* get another character */
  1901.    }
  1902. getout:
  1903.  
  1904.    ASSEMBLE {
  1905.         pop     si              /* get back si */
  1906.         pop     di              /* get back di */
  1907.         pop     ds              /* get back ds */
  1908.    }
  1909.  
  1910. /*
  1911.     * this next suggestion is part of chen's screen changes.
  1912.     *
  1913.     * screen_ptr = g_display.display_address + line * 160 + col * 2;
  1914.     *
  1915.     *              change to:
  1916.     *
  1917.    screen_ptr = g_display.display_address + line * (g_display.ncols*2) + col * 2;
  1918.    max_col = g_display.ncols;
  1919.    while (*s && col < max) {
  1920.       *screen_ptr++ = *s++;
  1921.       *screen_ptr++ = attr;
  1922.    }
  1923. */
  1924. }
  1925.  
  1926.  
  1927. /*
  1928.  * Name:    eol_clear
  1929.  * Purpose: To clear the line from col to max columns
  1930.  * Date:    June 5, 1991
  1931.  * Passed:  col:   column to begin clear
  1932.  *          line:  line to clear
  1933.  *          attr:  color to clear
  1934.  * Notes:   Basic assembly
  1935.  */
  1936. void eol_clear( int col, int line, int attr )
  1937. {
  1938. int  max_col;
  1939. void FAR *screen_ptr;
  1940. int  off;
  1941.  
  1942.    max_col = g_display.ncols;
  1943.    screen_ptr = (void FAR *)g_display.display_address;
  1944.    /*
  1945.     * this next suggestion is part of chen's screen changes.
  1946.     *
  1947.     * off = line * 160 + col * 2;
  1948.     *
  1949.     *              change to:
  1950.     */
  1951.    off = line * (g_display.ncols*2) + col * 2;
  1952.  
  1953.    ASSEMBLE {
  1954.         push    di                              /* save di on stack */
  1955.  
  1956.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1957.         mov     dx, WORD PTR col                /* put cols in dx */
  1958.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1959.         cmp     dx, cx                          /* max_cols < cols? */
  1960.         jge     getout                          /* no, thru with line */
  1961.         sub     cx, dx                          /* number of column to clear */
  1962.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1963.         add     di, WORD PTR off                /* add offset of line:col */
  1964.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1965.         mov     es, ax
  1966.         mov     ah, bl                          /* get attribute in ah */
  1967.         mov     al, ' '                         /* store ' ' in al */
  1968.         rep     stosw                           /* clear to end of line */
  1969.    }
  1970. getout:
  1971.  
  1972.    ASSEMBLE {
  1973.         pop     di                              /* get back di from stack */
  1974.    }
  1975.  
  1976. /*
  1977.    for (; col < g_display.ncols; col++) {
  1978.       *p++ = ' ';
  1979.       *p++ = attr;
  1980.    }
  1981. */
  1982. }
  1983.  
  1984.  
  1985. /*
  1986.  * Name:    window_eol_clear
  1987.  * Purpose: To clear the line from start_col to end_col
  1988.  * Date:    June 5, 1991
  1989.  * Passed:  window:  pointer to window
  1990.  *          attr:  color to clear
  1991.  * Notes:   Basic assembly
  1992.  */
  1993. void window_eol_clear( TDE_WIN *window, int attr )
  1994. {
  1995. int  max_col;
  1996. void FAR *screen_ptr;
  1997. int  off;
  1998.  
  1999.    if (!g_status.screen_display)
  2000.       return;
  2001.    screen_ptr = (void FAR *)g_display.display_address;
  2002.    /*
  2003.     * this next suggestion is part of chen's screen changes.
  2004.     *
  2005.     * off = window->cline * 160 + window->start_col * 2;
  2006.     *
  2007.     *              change to:
  2008.     */
  2009.    off = window->cline * (g_display.ncols*2) + window->start_col * 2;
  2010.    max_col = window->end_col + 1 - window->start_col;
  2011.  
  2012.    ASSEMBLE {
  2013.         push    di                              /* save di on stack */
  2014.  
  2015.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  2016.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  2017.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  2018.         add     di, WORD PTR off                /* add offset of line:col */
  2019.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  2020.         mov     es, ax
  2021.         mov     ah, bl                          /* get attribute in ah */
  2022.         mov     al, ' '                         /* store ' ' in al */
  2023.         rep     stosw                           /* clear to end of line */
  2024.  
  2025.         pop     di                              /* get back di from stack */
  2026.    }
  2027.  
  2028. /*
  2029.    for (max_col=window->start_col; max_col <= window->end_col; max_col++) {
  2030.       *screen_ptr++ = ' ';
  2031.       *screen_ptr++ = attr;
  2032.    }
  2033. */
  2034. }
  2035.  
  2036.  
  2037. /*
  2038.  * Name:    hlight_line
  2039.  * Date:    July 21, 1991
  2040.  * Passed:  x:     column to begin hi lite
  2041.  *          y:     line to begin hi lite
  2042.  *          lgth:  number of characters to hi lite
  2043.  *          attr:  attribute color
  2044.  * Notes:   The attribute byte is the hi byte.
  2045.  */
  2046. void hlight_line( int x, int y, int lgth, int attr )
  2047. {
  2048. int  off;
  2049. void FAR *screen_ptr;
  2050.  
  2051.    screen_ptr = (void FAR *)g_display.display_address;
  2052.    /*
  2053.     * this next suggestion is part of chen's screen changes.
  2054.     *
  2055.     * off = y * 160 + 2 * x + 1;
  2056.     *
  2057.     *              change to:
  2058.     */
  2059.    off = y * (g_display.ncols*2) + 2 * x + 1;  /* add one - so it points to attribute byte */
  2060.  
  2061.    ASSEMBLE {
  2062.         push    di              /* save di */
  2063.  
  2064.         mov     cx, lgth        /* number of characters to change color */
  2065.  
  2066.         mov     di, WORD PTR screen_ptr /* get destination - video memory */
  2067.         add     di, off                 /* add offset */
  2068.         mov     ax, WORD PTR screen_ptr+2
  2069.         mov     es, ax
  2070.         mov     ax, attr        /* attribute */
  2071.    }
  2072. lite_len:
  2073.  
  2074.    ASSEMBLE {
  2075.         stosb                   /* store a BYTE */
  2076.         inc     di              /* skip over character to next attribute */
  2077.         loop    lite_len        /* change next attribute */
  2078.         pop     di              /* restore di */
  2079.    }
  2080. }
  2081.  
  2082.  
  2083. /*
  2084.  * Name:    cls
  2085.  * Purpose: clear screen
  2086.  * Date:    June 5, 1991
  2087.  * Notes:   Call the video BIOS routine to clear the screen.
  2088.  */
  2089. void cls( void )
  2090. {
  2091. int  line;
  2092. unsigned char column;
  2093.  
  2094.    line = g_display.nlines + 1;
  2095.    /*
  2096.     * this next suggestion is part of chen's screen changes.
  2097.     *
  2098.     *              add:
  2099.     */
  2100.    column = (unsigned char)(g_display.ncols - 1);
  2101.  
  2102.    ASSEMBLE {
  2103.         xor     ch, ch                  /* starting row in ch = 0 */
  2104.         xor     cl, cl                  /* starting column in cl = 0 */
  2105.         mov     ax, WORD PTR line       /* get ending row */
  2106.         mov     dh, al                  /* put it in dh */
  2107.         mov     dl, Byte Ptr column     /* ending column in dl = 79 */
  2108.         mov     bh, 7                   /* attribute in bh  = 7 (normal) */
  2109.         mov     al, 0                   /* get number of lines */
  2110.         mov     ah, 6                   /* get function number */
  2111.         push    bp                      /* some BIOS versions wipe out bp */
  2112.         int     0x10
  2113.         pop     bp
  2114.    }
  2115. }
  2116.  
  2117.  
  2118. /*
  2119.  * Name:    set_cursor_size
  2120.  * Purpose: To set cursor size according to insert mode.
  2121.  * Date:    June 5, 1991
  2122.  * Passed:  csize:  desired cursor size
  2123.  * Notes:   use the global display structures to set the cursor size
  2124.  */
  2125. void set_cursor_size( int csize )
  2126. {
  2127.    ASSEMBLE {
  2128.         mov     ah, 1                   /* function 1 - set cursor size */
  2129.         mov     cx, WORD PTR csize      /* get cursor size ch:cl == top:bot */
  2130.         push    bp
  2131.         int     VIDEO_INT               /* video interrupt = 10h */
  2132.         pop     bp
  2133.    }
  2134. }
  2135.  
  2136.  
  2137. /*
  2138.  * Name:    set_overscan_color
  2139.  * Purpose: To set overscan color
  2140.  * Date:    April 1, 1993
  2141.  * Passed:  color:  overscan color
  2142.  * Notes:   before setting the overscan color, the old overscan color
  2143.  *           needs to be saved so it can be restored.
  2144.  */
  2145. void set_overscan_color( int color )
  2146. {
  2147.    ASSEMBLE {
  2148.         mov     ah, 0x0b                /* function 0x0b */
  2149.         mov     bl, BYTE PTR color      /* get new overscan color */
  2150.         xor     bh, bh
  2151.         push    bp
  2152.         int     VIDEO_INT               /* video interrupt = 10h */
  2153.         pop     bp
  2154.    }
  2155. }
  2156.  
  2157.  
  2158. /*
  2159.  * Name:    save_screen_line
  2160.  * Purpose: To save the characters and attributes of a line on screen.
  2161.  * Date:    June 5, 1991
  2162.  * Passed:  col:    desired column, usually always zero
  2163.  *          line:   line on screen to save (0 up to max)
  2164.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  2165.  * Notes:   Save the contents of the line on screen where prompt is
  2166.  *           to be displayed
  2167.  */
  2168. void save_screen_line( int col, int line, char *screen_buffer )
  2169. {
  2170. char FAR *p;
  2171.  
  2172.    /*
  2173.     * this next suggestion is part of chen's screen changes.
  2174.     *
  2175.     * p = g_display.display_address + line * 160 + col * 2;
  2176.     * _fmemcpy( screen_buffer, p, 160 );
  2177.     *
  2178.     *              change to:
  2179.     */
  2180.    p = g_display.display_address + line * (g_display.ncols*2) + col * 2;
  2181.    _fmemcpy( screen_buffer, p, (g_display.ncols*2) );
  2182. }
  2183.  
  2184.  
  2185. /*
  2186.  * Name:    restore_screen_line
  2187.  * Purpose: To restore the characters and attributes of a line on screen.
  2188.  * Date:    June 5, 1991
  2189.  * Passed:  col:    usually always zero
  2190.  *          line:   line to restore (0 up to max)
  2191.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  2192.  * Notes:   Restore the contents of the line on screen where the prompt
  2193.  *           was displayed
  2194.  */
  2195. void restore_screen_line( int col, int line, char *screen_buffer )
  2196. {
  2197. char FAR *p;
  2198.  
  2199.    /*
  2200.     * this next suggestion is part of chen's screen changes.
  2201.     *
  2202.     * p = g_display.display_address + line * 160 + col * 2;
  2203.     * _fmemcpy( p, screen_buffer, 160 );
  2204.     *
  2205.     *              change to:
  2206.     */
  2207.    p = g_display.display_address + line * (g_display.ncols*2) + col * 2;
  2208.    _fmemcpy( p, screen_buffer, (g_display.ncols*2) );
  2209. }
  2210.  
  2211.  
  2212. /*
  2213.  * Name:    save_minor_area
  2214.  * Purpose: save text and attribute under the pulled menu
  2215.  * Date:    November 13, 1993
  2216.  * Passed:  buffer: storage for text and attribute
  2217.  *          wid: width of the pulled menu
  2218.  *          len: length of pulled menu
  2219.  *          row: starting row of pulled menu
  2220.  *          col: starting column of pulled menu
  2221.  * Notes:   assume 80 column mode
  2222.  */
  2223. void save_minor_area( int *buffer, int wid, int len, int row, int col )
  2224. {
  2225. int off;
  2226. int FAR *pointer;
  2227. int i;
  2228. int j;
  2229.  
  2230.    wid--;
  2231.    /*
  2232.     * this next suggestion is part of chen's screen changes.
  2233.     *
  2234.     * off = row * 80 + col;
  2235.     *
  2236.     *              change to:
  2237.     */
  2238.    off = row * g_display.ncols + col;
  2239.    pointer = (int FAR *)g_display.display_address + off;
  2240.    for (i=0; len > 0; len--) {
  2241.       for (j=wid; j >= 0; j--, i++)
  2242.          buffer[i] = pointer[j];
  2243.       pointer += g_display.ncols;
  2244.    }
  2245. }
  2246.  
  2247.  
  2248. /*
  2249.  * Name:    retore_minor_area
  2250.  * Purpose: restore text and attribute under the pulled menu
  2251.  * Date:    November 13, 1993
  2252.  * Passed:  buffer: storage for text and attribute
  2253.  *          wid: width of the pulled menu
  2254.  *          len: length of pulled menu
  2255.  *          row: starting row of pulled menu
  2256.  *          col: starting column of pulled menu
  2257.  * Notes:   assume 80 column mode
  2258.  */
  2259. void restore_minor_area( int *buffer, int wid, int len, int row, int col )
  2260. {
  2261. int off;
  2262. int FAR *pointer;
  2263. int i;
  2264. int j;
  2265.  
  2266.    wid--;
  2267.    /*
  2268.     * this next suggestion is part of chen's screen changes.
  2269.     *
  2270.     * off = row * 80 + col;
  2271.     *
  2272.     *              change to:
  2273.     */
  2274.    off = row * g_display.ncols + col;
  2275.    pointer = (int FAR *)g_display.display_address + off;
  2276.    for (i=0; len > 0; len--) {
  2277.       for (j=wid; j >= 0; j--, i++)
  2278.          pointer[j] = buffer[i];
  2279.       pointer += g_display.ncols;
  2280.    }
  2281. }
  2282.  
  2283. #endif
  2284.  
  2285. /*
  2286.  **********************************************************************
  2287.  ******************************  PART 3  ******************************
  2288.  **********************************************************************
  2289.  *
  2290.  * System independent keyboard stuff.
  2291.  */
  2292.  
  2293.  
  2294. /*
  2295.  * Name:    getfunc
  2296.  * Purpose: get the function assigned to key c
  2297.  * Date:    July 11, 1991
  2298.  * Passed:  c:  key just pressed
  2299.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  2300.  *           The codes in the range 0-255 are ASCII and extended ASCII chars.
  2301.  */
  2302. int  getfunc( int c )
  2303. {
  2304. register int i = c;
  2305. int  key_found;
  2306.  
  2307.    if (!g_status.key_pending) {
  2308.       i = c;
  2309.       if (i <= 256)
  2310.          i = 0;
  2311.       else
  2312.          i = key_func.key[i-256];
  2313.    } else {
  2314.  
  2315.       /*
  2316.        * allow the user to enter two-key combinations
  2317.        */
  2318.       key_found = FALSE;
  2319.       for (i=0; i < MAX_TWO_KEYS; i++) {
  2320.          if (g_status.first_key == two_key_list.key[i].parent_key &&
  2321.                                c == two_key_list.key[i].child_key) {
  2322.             i = two_key_list.key[i].func;
  2323.             key_found = TRUE;
  2324.             break;
  2325.          }
  2326.       }
  2327.       if (key_found == FALSE)
  2328.          i = ERROR;
  2329.    }
  2330.    return( i );
  2331. }
  2332.  
  2333.  
  2334. /*
  2335.  * Name:    two_key
  2336.  * Purpose: set the two_key flag and prompt for the next key.
  2337.  * Date:    April 1, 1992
  2338.  * Notes:   this function accepts two key commands.
  2339.  */
  2340. int  two_key( TDE_WIN *arg_filler )
  2341. {
  2342.    s_output( console1, g_display.mode_line, 67, g_display.diag_color );
  2343.    g_status.key_pending = TRUE;
  2344.    g_status.first_key = g_status.key_pressed;
  2345.    return( OK );
  2346. }
  2347.  
  2348.  
  2349. /*
  2350.  * Name:     getanswerkey
  2351.  * Purpose:  To get answer to questions etc.
  2352.  * Author:   Byrial Jensen
  2353.  * Date:     September 2, 1993
  2354.  * Modified: Frank Davis, November 13, 1993 (comments and bj_toupper())
  2355.  * Returns:  The pressed key, changed to uppercase if alfabetic
  2356.  * Notes:    If a key of a macro starting with:
  2357.  *             IfCapsLock character, or IfNotCapsLock character
  2358.  *           is presed, the character will be returned, changed to uppercase
  2359.  *           if a letter.
  2360.  */
  2361. int  getanswerkey( void )
  2362. {
  2363. int key;
  2364. int macrokey;
  2365. int macrofunc;
  2366. int macronext;
  2367.  
  2368.    /*
  2369.     * get a response from the user.  if ascii or extended ascii, return upper
  2370.     */
  2371.    key = getkey( );
  2372.    if (key <= 255)
  2373.       key = bj_toupper( key );
  2374.  
  2375.    /*
  2376.     * else if key is assigned a character via macro, return upper key
  2377.     */
  2378.    else if (getfunc( key ) == PlayBack) {
  2379.       macronext = macro.first_stroke[key - 256];
  2380.       macrokey = macro.strokes[macronext].key;
  2381.       macrofunc = getfunc( macrokey );
  2382.  
  2383.       /*
  2384.        * if this a letter, return upper.
  2385.        */
  2386.       if (macrofunc == IfCapsLock || macrofunc == IfNotCapsLock) {
  2387.          macronext = macro.strokes[macronext].next;
  2388.          if (macronext != -1) {
  2389.             macrokey = macro.strokes[macronext].key;
  2390.             if (macrokey <= 255)
  2391.                key = bj_toupper( macrokey );
  2392.          }
  2393.       }
  2394.    }
  2395.    return( key );
  2396. }
  2397.